package com.xyf.sys.controller;

import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import com.xyf.sys.config.CustomException;
import com.xyf.sys.config.MiniprogramConfig;
import com.xyf.sys.domain.Order;
import com.xyf.sys.domain.OrderProduct;
import com.xyf.sys.domain.Role;
import com.xyf.sys.enums.DeliveryEnum;
import com.xyf.sys.service.*;
import com.xyf.sys.util.R;
import com.xyf.sys.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author R-H
 * @Date 2024/2/241748
 * @Description
 */
@RestController
@RequestMapping("/order")
@Slf4j
@Api(tags = "订单相关")
public class OrderController {

    @Autowired
    private IOrderService orderService;
    @Autowired
    private IOrderProductService orderProductService;
    @Autowired
    private ILogisticService logisticService;
    @Autowired
    private Config defaultConfig;
    @Autowired
    private Config laundryConfig;
    @Autowired
    private Config deliveryConfig;
    @Autowired
    private ITencentCloudService tencentCloudService;
    @Autowired
    private IRoleService roleService;
    @Autowired
    private IOrderLogisticsService orderLogisticsService;
    @Autowired
    @Qualifier(value = "clientConfig")
    private MiniprogramConfig.MiniConfig clientConfig;
    @Autowired
    @Qualifier(value = "manageConfig")
    private MiniprogramConfig.MiniConfig manageConfig;
    @Autowired
    private IDownloadTaskService downloadTaskService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IUserRoleService userRoleService;


    @ApiOperation("生成预订单")
    @PostMapping("/pre")
    public Object preOrder(@RequestBody PreOrderVo orderVo, HttpServletRequest request) {
        orderVo.setFromAppid(request.getHeader("APPID"));
        orderVo.setUserId(request.getHeader("openid"));
        return R.ok(orderService.preOrder(orderVo));
    }

    @ApiOperation("查询订单列表")
    @PostMapping("/list")
    public Object list(@RequestBody OrderListRequestVo requestVo, HttpServletRequest request) {
        String appid = request.getHeader("APPID");
        requestVo.setClient(clientConfig.getAppid().equals(appid));
        if (requestVo.getRoleId() != null) {
            Role role = roleService.getRole(requestVo.getRoleId());
            if (role != null) {
                requestVo.setRoleKey(role.getRoleKey());
            }
        }
        if (requestVo.getClient()){
            requestVo.setRoleKey("USER");
        } else if (StringUtils.isBlank(requestVo.getRoleKey())) {
            requestVo.setRoleKey("REGIMENT");
            List<Role> roleList = userRoleService.getRoleList(requestVo.getUserId(), requestVo.getDeptId());
            roleList = roleList.stream().filter(r -> !"USER".equalsIgnoreCase(r.getRoleKey())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(roleList) && roleList.size() == 1){
                requestVo.setRoleKey(roleList.get(0).getRoleKey());
            }
//            requestVo.setRoleKey(roleList == null || roleList.size() == 0 ? null : roleList.get(0).getRoleKey());
        }
        if (requestVo.getQueryType() == 1){
            requestVo.setUserId(appid.equals(clientConfig.getAppid()) ? requestVo.getUserId() : null);
            requestVo.setDeptId(appid.equals(clientConfig.getAppid()) ? null : requestVo.getDeptId());
        }
        PageHelper.startPage(requestVo.getPageNum(), requestVo.getPageSize());
        List<OrderVo> orderList = orderService.getList(requestVo);
        PageInfo pageInfo = new PageInfo(orderList);
        return R.ok(pageInfo);
    }

    @ApiOperation("聚合查询")
    @PostMapping("/aggregateQuery")
    public Object aggregateQuery(@RequestBody OrderListRequestVo requestVo, HttpServletRequest request) {
        String appid = request.getHeader("APPID");
        if (requestVo.getQueryType() == 1){
            requestVo.setUserId(appid.equals(clientConfig.getAppid()) ? requestVo.getUserId() : null);
            requestVo.setDeptId(appid.equals(clientConfig.getAppid()) ? null : requestVo.getDeptId());
        }
        PageHelper.startPage(requestVo.getPageNum(), requestVo.getPageSize());
        List<OrderVo> orderList = orderService.aggregateQuery(requestVo);
        PageInfo pageInfo = new PageInfo(orderList);
        return R.ok(pageInfo);
    }

    /**
     * 微信支付回调
     *
     * @param body
     * @param request
     * @return
     */
    @RequestMapping("/payNotify")
    @ResponseBody
    public R orderCallback(@RequestBody Map body, HttpServletRequest request) {
        log.info("JSONObject.parseObject(body).toJSONString() = " + JSONObject.toJSONString(body));
        String characterEncoding = request.getCharacterEncoding();
        log.info("characterEncoding=" + characterEncoding);
        //从请求头获取验签字段
        String Timestamp = request.getHeader("Wechatpay-Timestamp");
        String Nonce = request.getHeader("Wechatpay-Nonce");
        String Signature = request.getHeader("Wechatpay-Signature");
        String Serial = request.getHeader("Wechatpay-Serial");
        System.out.println("开始读取请求头的信息");
        //请求头
        log.info("Wechatpay-Timestamp=" + Timestamp);
        log.info("Wechatpay-Nonce=" + Nonce);
        log.info("Wechatpay-Signature=" + Signature);
        log.info("Wechatpay-Serial=" + Serial);

        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(Serial)
                .nonce(Nonce)
                .signature(Signature)
                .timestamp(Timestamp)
                .body(JSONObject.toJSONString(body))
                .build();
        Transaction transaction = null;
        try {
            NotificationParser parser = new NotificationParser((RSAAutoCertificateConfig) defaultConfig);
            transaction = parser.parse(requestParam, Transaction.class);
        } catch (Exception e) {
        }
        if (transaction == null){
            try {
                NotificationParser parser = new NotificationParser((RSAAutoCertificateConfig) deliveryConfig);
                transaction = parser.parse(requestParam, Transaction.class);
            } catch (Exception e) {
            }
        }
        if (transaction == null){
            try {
                NotificationParser parser = new NotificationParser((RSAAutoCertificateConfig) laundryConfig);
                transaction = parser.parse(requestParam, Transaction.class);
            } catch (Exception e) {
            }
        }
        log.info("pay notify transaction = " + JSONObject.toJSONString(transaction));
        return orderService.callback(transaction) ? R.ok() : R.fail(500, "回调失败");

    }


    /**
     * 微信退款回调
     *
     * @param body
     * @param request
     * @return
     */
    @RequestMapping("/refundNotify")
    @ResponseBody
    public Object refundCallback(@RequestBody Map body, HttpServletRequest request) {
        try {
            log.info("JSONObject.parseObject(body).toJSONString() = " + JSONObject.toJSONString(body));
            String characterEncoding = request.getCharacterEncoding();
            log.info("characterEncoding=" + characterEncoding);
            //从请求头获取验签字段
            String Timestamp = request.getHeader("Wechatpay-Timestamp");
            String Nonce = request.getHeader("Wechatpay-Nonce");
            String Signature = request.getHeader("Wechatpay-Signature");
            String Serial = request.getHeader("Wechatpay-Serial");
            System.out.println("开始读取请求头的信息");
            //请求头
            log.info("Wechatpay-Timestamp=" + Timestamp);
            log.info("Wechatpay-Nonce=" + Nonce);
            log.info("Wechatpay-Signature=" + Signature);
            log.info("Wechatpay-Serial=" + Serial);
            System.out.println("=================");
            // 构造 RequestParam
            com.wechat.pay.java.core.notification.RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(Serial)
                    .nonce(Nonce)
                    .signature(Signature)
                    .timestamp(Timestamp)
                    .body(JSONObject.toJSONString(body))
                    .build();
            RefundNotification transaction = null;
            try {
                NotificationParser parser = new NotificationParser((RSAAutoCertificateConfig) defaultConfig);
                transaction = parser.parse(requestParam, RefundNotification.class);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (transaction == null){
                try {
                    NotificationParser parser = new NotificationParser((RSAAutoCertificateConfig) deliveryConfig);
                    transaction = parser.parse(requestParam, RefundNotification.class);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (transaction == null){
                try {
                    NotificationParser parser = new NotificationParser((RSAAutoCertificateConfig) laundryConfig);
                    transaction = parser.parse(requestParam, RefundNotification.class);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            log.info("refund notify transaction = " + JSONObject.toJSONString(transaction));
            return orderService.refundNotification(transaction) ? R.ok() : R.fail(500, "回调失败");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.fail(500, "回调失败");
    }

    @ApiOperation("获取订单价格")
    @PostMapping("/previewPrice")
    public Object getOrderPrice(@RequestBody OrderPreviewVo requestVo) {
        return R.ok(orderService.previewPrice(requestVo));
    }

    @ApiOperation("查询订单接口")
    @GetMapping("/query")
    public Object query(@org.springframework.web.bind.annotation.RequestParam String orderId) {
        return R.ok(orderService.getDetail(orderId));
    }

    @ApiOperation("查询订单接口")
    @GetMapping("/outTradeNoQuery")
    public Object outTradeNoQuery(@org.springframework.web.bind.annotation.RequestParam String orderId) {
        return R.ok(orderService.getDetail(orderId));
    }


    @ApiOperation("获取支付参数")
    @PostMapping("/pay")
    public Object pay(@RequestBody OrderRequestVo requestVo, HttpServletRequest request) {
        String openid = request.getHeader("OPENID");
        return R.ok(orderService.pay(requestVo.getOrderId(), openid, request.getHeader("APPID")));
    }


    @ApiOperation("退款接口")
    @PostMapping("/refund")
    public Object refund(@RequestBody OrderRequestVo refundRequestVo) {
        return R.ok(orderService.orderRefund(refundRequestVo));
    }


    @ApiOperation("取消订单")
    @PostMapping("/cancel")
    public Object cancel(@RequestBody OrderRequestVo requestVo, HttpServletRequest request) {
        String appId = request.getHeader("APPID");
        requestVo.setAppid(appId);
        String secret = appId.equals(clientConfig.getAppid()) ? clientConfig.getSecret() : manageConfig.getSecret();
        requestVo.setSecret(secret);
        Order order = orderService.get(requestVo.getOrderId());
        List<OrderProduct> orderProductList = orderProductService.getOrderProductList(order.getId());
        if (order.getOrderType() == 1) {
            OrderProduct product = orderProductList.get(0);
            String deliveryId = product.getDeliveryId();
            String waybillId = product.getWaybillId();
            if (StringUtils.isNotBlank(waybillId)) {
                List<OrderLogisticStep> logistic = logisticService.queryLogistic(order.getId(), product.getDeliveryId(), product.getWaybillId(), requestVo.getAppid(), requestVo.getSecret(), requestVo.getUserId());
                boolean hasLogistics = !CollectionUtils.isEmpty(logistic);
                if (hasLogistics) {
                    boolean isJD = DeliveryEnum.JD.toString().equals(deliveryId);
                    if (!isJD || (logistic.size() >= 2 &&
                            logistic.stream().noneMatch(v -> "200052".equalsIgnoreCase(v.getStatus())))) {
                        throw new CustomException("检测到单号【" + product.getWaybillId() + "】已发生物流轨迹无法取消");
                    }
                } else {
                    Boolean bool = null;
                    try {
                        if (DeliveryEnum.SF.toString().equals(deliveryId)) {
                            bool = logisticService.cancelSfOrder(order.getId(), deliveryId, waybillId, requestVo.getAppid(), requestVo.getSecret(), requestVo.getUserId());
                        } else {
                            bool = logisticService.cancelOrder(order.getId(), deliveryId, waybillId);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("order id {} 取消失败 {} ", order.getId(), e.getMessage());
                    }
                }
            }
        }
        return R.ok(orderService.cancel(requestVo));
    }

    @ApiOperation("删除订单")
    @PostMapping("/remove")
    public Object remove(@RequestBody OrderRequestVo requestVo) {
        return R.ok(orderService.remove(requestVo.getOrderId(), requestVo.getUserId()));
    }

    @ApiOperation("修改订单")
    @PostMapping("/set")
    public Object edit(@RequestBody OrderVo body) {
        return R.ok(orderService.edit(body));
    }

    @ApiOperation("增加打印次数")
    @PostMapping("/incrPrintTimes")
    public Object incrPrintTimes(@RequestBody OrderRequestVo orderRequestVo) {
        return R.ok(orderService.incrPrintTimes(orderRequestVo));
    }

    @ApiOperation("电子面单打印")
    @PostMapping("/print")
    public Object print(@RequestBody OrderPrint orderPrint) {
        return R.ok(logisticService.print(orderPrint.getOrderId(), orderPrint.getPrinterId(), orderPrint.getUserId(), orderPrint.getDeptId()));
    }

    @ApiOperation("收款记录")
    @PostMapping("/paymentList")
    public R paymentList(@RequestBody PaymentListRequest request) {
        return R.ok(orderService.paymentList(request.getStartDate(), request.getEndDate(), request.getUserId(), request.getDeptId(), request.getCheckType()));
    }

    @ApiOperation("收款记录详情")
    @PostMapping("/paymentDetail")
    public R paymentDetail(@RequestBody PaymentRequest body, HttpServletRequest request) {
        PageHelper.startPage(body.getPageNum(), body.getPageSize());
        List<OrderPayment> list = orderService.paymentDetailList(body.getDate(), body.getDate(), body.getType(), body.getUserId(), body.getDeptId(), Long.valueOf(request.getHeader("DEPTID")), body.getCheckType());
        PageInfo<OrderPayment> pageInfo = new PageInfo<>(list);
        return R.ok(pageInfo);
    }

    @ApiOperation("收款记录导出")
    @PostMapping("/paymentExport")
    public R paymentExport(@RequestBody PaymentListRequest body, HttpServletRequest request) {
        return R.ok(downloadTaskService.createTask(body.getStartDate(), body.getEndDate(), body.getType(), body.getUserId(), body.getSubUserId(), 1, Long.valueOf(request.getHeader("DEPTID")), body.getDeptId(), body.getCheckType()));
//        // 设置响应头信息
//        response.setContentType("application/octet-stream");
//        String encodedFilename = URLEncoder.encode(file.getName(), "UTF-8").replaceAll("\\+", "%20");
//        response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFilename+ "\"");
//        // 获取文件输入流
//        try (FileInputStream inputStream = new FileInputStream(filePath);
//             OutputStream outputStream = response.getOutputStream()) {
//
//            // 读取文件内容并写入响应输出流
//            byte[] buffer = new byte[4096];
//            int bytesRead;
//            while ((bytesRead = inputStream.read(buffer)) != -1) {
//                outputStream.write(buffer, 0, bytesRead);
//            }
//            // 刷新输出流，确保所有数据都已发送
//            outputStream.flush();
//        }
    }

    @ApiOperation("对账")
    @PostMapping("/billVerify")
    public Object billVerify(@RequestBody Map<String, String> body, HttpServletRequest request) {
        return R.ok(downloadTaskService.createTask(body.get("billExcelUrl"), body.get("userId"), Long.valueOf(body.get("deptId"))));
    }

    @ApiOperation("写入订单重量")
    @PostMapping("/writeWeight")
    public Object writeWeight(@RequestBody Map<String, String> body, HttpServletRequest request) {
        return R.ok(downloadTaskService.createOrderWeightWriteTask(body.get("url"), request.getHeader("openid"), Long.valueOf(body.get("deptId"))));
    }

/*    @ApiOperation("扫码")
    @PostMapping("/logisticsEventUpdate")
    public Object logisticsEventUpdate(@RequestBody OrderLogisticsUpdate orderLogistics) {
        return R.ok(orderService.logisticsEventUpdate(orderLogistics.getOutTradeNo(), null, orderLogistics.getUserId()));
    }*/

    @ApiOperation("物流订单查询")
    @PostMapping("/logisticsOrder")
    public Object logisticsOrder(@RequestBody LogisticsListRequest requestVo) {
        PageHelper.startPage(requestVo.getPageNum(), requestVo.getPageSize());
        List<OrderVo> orderLogistics = orderLogisticsService.getLogisticsOrderList(requestVo);
        return R.ok(new PageInfo(orderLogistics));
    }

    @ApiOperation("下单")
    @PostMapping("/assistOrder")
    public Object assistOrder(@RequestBody PreOrderVo body, HttpServletRequest request) {
        body.setAppid(request.getHeader("APPID"));
        return R.ok(orderService.createAssistOrder(body));
    }

    @ApiOperation("确认")
    @PostMapping("/confirm")
    public Object confirm(@RequestBody ConfirmOrder body, HttpServletRequest request) {
        return R.ok(orderService.confirmOrder(body.getOrderId(), body.getUserId()));
    }

    @ApiOperation("绑定订单码")
    @PostMapping("/orderProductCode")
    public Object orderProductCode(@RequestBody OrderProductCodeVo codeVo, HttpServletRequest request) {
        return R.ok(orderService.updateOrderProductCode(codeVo));
    }

    @ApiOperation("根据条码查询订单接口")
    @GetMapping("/orderProductCodeQuery")
    public Object orderProductCodeQuery(@org.springframework.web.bind.annotation.RequestParam String code) {
        return R.ok(orderService.findOrderByOrderProductCode(code));
    }


    @ApiOperation("订单记录导出")
    @PostMapping("/export")
    public R export(@RequestBody OrderExport body, HttpServletRequest request) {
        return R.ok(downloadTaskService.createOrderExportTask(body, Long.valueOf(request.getHeader("DEPTID"))));
    }

    @ApiOperation("确认发货")
    @PostMapping("/shipments")
    public R shipments(@RequestBody OrderVo body, HttpServletRequest request) {
        orderService.orderShipments(body.getOrderId(), body.getUserId());
        return R.ok();
    }

    @ApiOperation("确认收货")
    @PostMapping("/receiveNotify")
    public R te(@RequestBody OrderVo body, HttpServletRequest request) {
        orderService.receiveNotify(body.getOrderId(), body.getUserId());
        return R.ok();
    }

}
